package chapter21.performance;

import java.util.*;
import java.util.concurrent.*;

public abstract class Tester<C> {
	static int testReps = 10;
	static int testCycles = 1000;
	static int containerSize = 1000;
	abstract C containerInitializer();
	abstract void startReadersAndWriters();
	C testContainer;
	String testId;
	int nReaders;
	int nWriters;
	volatile long readResult = 0;
	volatile long readTime = 0;
	volatile long writeTime = 0;
	CountDownLatch endlatch;
	static ExecutorService exec = Executors.newCachedThreadPool();
	Integer[] writeData;
	
	Tester(String testId, int nReaders, int nWriters) {
		this.testId = testId + " " + nReaders + "r " + nWriters + "w";
		this.nReaders = nReaders;
		this.nWriters = nWriters;
		Random rand = new Random(47);
		for(int i = 0; i < containerSize; i++)
			writeData[i] = rand.nextInt();
		for(int i = 0; i < testReps; i++) {
			runTest();
			readTime = 0;
			writeTime = 0;
		}
	}
	
	void runTest() {
		endlatch = new CountDownLatch(nReaders + nWriters);
		testContainer = containerInitializer();
		startReadersAndWriters();
		try {
			endlatch.await();
		} catch (InterruptedException e) {
			System.out.println("endlatch interrupted");
		}
		System.out.printf("%-27s %14d\n",
				"readTime + writeTime =", readTime + writeTime);
	}
	
	abstract class TestTask implements Runnable {
		abstract void test();
		abstract void putResults();
		long duration;
		
		@Override
		public void run() {
			long startTime = System.nanoTime();
			test();
			duration = System.nanoTime() - startTime;
			synchronized (Tester.this) {
				putResults();
			}
			endlatch.countDown();
		}
	}
	
	public static void initMain(String[] args) {
		if(args.length > 0)
			testReps = new Integer(args[0]);
		if(args.length > 1)
			testCycles = new Integer(args[1]);
		if(args.length > 2)
			containerSize = new Integer(args[2]);
		System.out.printf("%-27s %14s %14s\n",
				"Type", "Read Time", "Write Time");
	}
}
